using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Net.System;
using Net.Helper;
using Net.Serialize;

namespace Binding
{
    public readonly struct SerializeTestingTestBind : ISerialize<SerializeTesting.Test>, ISerialize
    {
        public ushort HashCode { get { return 1001; } }

        public void Bind()
		{
			SerializeCache<SerializeTesting.Test>.Serialize = this;
		}

        public unsafe void Write(SerializeTesting.Test value, ISegment stream)
        {
            var isDefault = value == default;
	        stream.Write(isDefault);
	        if (isDefault) return;

            var address = Unsafe.AsPointer(ref value);
			address = (void*)(Unsafe.Read<long>(address) + 8);
            fixed (byte* ptr = &stream.Buffer[stream.Position]) 
            {
                var offset = 101;
                Unsafe.CopyBlock(ptr, address, (uint)offset);
 //1
                NetConvertHelper.Write(ptr, ref offset, value.f13);
 //1
                NetConvertHelper.Write(ptr, ref offset, value.f14);
 //1
                NetConvertHelper.Write(ptr, ref offset, value.f15);
 //2
                stream.Position += offset;
 //3
                isDefault = value.test == default;
                stream.Write(isDefault);
                if (!isDefault)
                    SerializeCache<SerializeTesting.Test>.Serialize.Write(value.test, stream);
 //3
                isDefault = value.testArray == default;
                stream.Write(isDefault);
                if (!isDefault)
                    SerializeCache<SerializeTesting.Test[]>.Serialize.Write(value.testArray, stream);
 //3
                isDefault = value.testList == default;
                stream.Write(isDefault);
                if (!isDefault)
                    SerializeCache<System.Collections.Generic.List<SerializeTesting.Test>>.Serialize.Write(value.testList, stream);
 //4
            }
        }
		
        public SerializeTesting.Test Read(ISegment stream) 
        {
            var value = new SerializeTesting.Test();
            Read(ref value, stream);
            return value;
        }

		public unsafe void Read(ref SerializeTesting.Test value, ISegment stream)
		{
            var isDefault = stream.ReadBoolean();
            if (isDefault)
            {
                value = default;
                return;
            }

            var address = Unsafe.AsPointer(ref value);
			address = (void*)(Unsafe.Read<long>(address) + 8);
			fixed (byte* ptr = &stream.Buffer[stream.Position]) 
            {
                var offset = 101;
                Unsafe.CopyBlock(address, ptr, (uint)offset);
 //5
                value.f13 = NetConvertHelper.Read<System.DateTime>(ptr, ref offset);
 //5
                value.f14 = NetConvertHelper.Read<System.Decimal>(ptr, ref offset);
 //5
                value.f15 = NetConvertHelper.Read(ptr, ref offset);
 //6
                stream.Position += offset;
 //7
                if (!stream.ReadBoolean())
                    value.test = SerializeCache<SerializeTesting.Test>.Serialize.Read(stream);
 //7
                if (!stream.ReadBoolean())
                    value.testArray = SerializeCache<SerializeTesting.Test[]>.Serialize.Read(stream);
 //7
                if (!stream.ReadBoolean())
                    value.testList = SerializeCache<System.Collections.Generic.List<SerializeTesting.Test>>.Serialize.Read(stream);
 //8
            }
		}

        public void WriteValue(object value, ISegment stream)
        {
            Write((SerializeTesting.Test)value, stream);
        }

        public object ReadValue(ISegment stream)
        {
            return Read(stream);
        }
    }
}

namespace Binding
{
	public readonly struct SerializeTestingTestArrayBind : ISerialize<SerializeTesting.Test[]>, ISerialize
	{
        public ushort HashCode { get { return 1002; } }

        public void Bind()
		{
			SerializeCache<SerializeTesting.Test[]>.Serialize = this;
		}

		public void Write(SerializeTesting.Test[] value, ISegment stream)
		{
			int count = value.Length;
			stream.Write(count);
			if (count == 0) return;
			var bind = new SerializeTestingTestBind();
			foreach (var value1 in value)
				bind.Write(value1, stream);
		}

		public SerializeTesting.Test[] Read(ISegment stream)
		{
			var count = stream.ReadInt32();
			var value = new SerializeTesting.Test[count];
			if (count == 0) return value;
			var bind = new SerializeTestingTestBind();
			for (int i = 0; i < count; i++)
				value[i] = bind.Read(stream);
			return value;
		}

		public void WriteValue(object value, ISegment stream)
		{
			Write((SerializeTesting.Test[])value, stream);
		}

		public object ReadValue(ISegment stream)
		{
			return Read(stream);
		}
	}
}

namespace Binding
{
	public readonly struct SystemCollectionsGenericListSerializeTestingTestBind : ISerialize<System.Collections.Generic.List<SerializeTesting.Test>>, ISerialize
	{
        public ushort HashCode { get { return 1003; } }

        public void Bind()
		{
			SerializeCache<System.Collections.Generic.List<SerializeTesting.Test>>.Serialize = this;
		}

		public void Write(System.Collections.Generic.List<SerializeTesting.Test> value, ISegment stream)
		{
			int count = value.Count;
			stream.Write(count);
			if (count == 0) return;
			var bind = new SerializeTestingTestBind();
			foreach (var value1 in value)
				bind.Write(value1, stream);
		}

		public System.Collections.Generic.List<SerializeTesting.Test> Read(ISegment stream)
		{
			var count = stream.ReadInt32();
			var value = new System.Collections.Generic.List<SerializeTesting.Test>(count);
			if (count == 0) return value;
			var bind = new SerializeTestingTestBind();
			for (int i = 0; i < count; i++)
				value.Add(bind.Read(stream));
			return value;
		}

		public void WriteValue(object value, ISegment stream)
		{
			Write((System.Collections.Generic.List<SerializeTesting.Test>)value, stream);
		}

		public object ReadValue(ISegment stream)
		{
			return Read(stream);
		}
	}
}
